using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Configuration;
using MindFactorial.LaunchPoint.Runtime;
using MindFactorial.LaunchPoint.Common;
using MindFactorial.LaunchPoint.Console.Library;
using System.Reflection;
using System.Xml;

namespace MindFactorial.LaunchPoint.Console
{
    public class StartupApplication : LaunchPointApplication
    {
        //ConsoleShell _shell;
        ConsoleWindow _window;
        object _last_waitcontext;
        Dictionary<object, object> _wait_context_list = new Dictionary<object,object>();
        Queue<object> _wait_q = new Queue<object>();

        System.Collections.Hashtable languages;
        System.Collections.Hashtable cultureInfo;
        
        /// <summary>
        /// Start of the plugin execution
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        public override int Startup(params string[] args)
        {
            //System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("ja-JP");

            languages = new System.Collections.Hashtable();
            languages.Add("English", "en-US");
            languages.Add("Japanese", "ja-JP");
            languages.Add("Chinese", "zh-CN");
            languages.Add("Spanish", "es-ES");
            languages.Add("German", "de-DE");
            languages.Add("French", "fr-FR");

            cultureInfo = new System.Collections.Hashtable();
            cultureInfo.Add("en-US", "1");
            cultureInfo.Add("ja-JP", "2");
            cultureInfo.Add("zh-CN", "3");
            cultureInfo.Add("es-ES", "4");
            cultureInfo.Add("de-DE", "5");
            cultureInfo.Add("fr-FR", "6");

            //instantiate the main console window and set it's closed event
            _window = new ConsoleWindow(this);
            _window.Closed += delegate(object sender, EventArgs e)
            {
                Application.Exit();
            };

            SplashScreen splash = new SplashScreen(new System.Threading.ThreadStart(InitializeConsole));
            if (splash.ShowDialog() == true)
            {
                try
                {
                    
                    _window.ShowDialog();
                    return 0;
                }
                catch (Exception ex)
                {
                    //force window to stop waiting
                    ForceHide();
                    throw ex;
                }
            }
            else
            {
                Logger.Log("B50964BA-9E6B-4632-9687-C65E7C3E423C: Runnable Application with configuration {0} is shutting down because splash screen could not return as expected", ClientConfiguration.ToString());
                return -1;
            }
        }

        internal void InitializeConsole()
        {
            foreach (PluginConfig pluginnodetarget in ClientConfiguration.Plugins)
            {
                string name = pluginnodetarget.Name;

                //initialize shell and prepopulate all built in plugins
                ConsoleShell shell = new ConsoleShell(this, _window);




                //load all dynamic plugins
                foreach (PluginConfig pluginNode in ClientConfiguration.Plugins)
                {
                    try
                    {
                        pluginNode.Label = Properties.Resources.ResourceManager.GetString(pluginNode.Label);
                        ConsolePlugIn plugin = ConsolePlugIn.LoadPlugin(pluginNode, shell);


                        //if the plugin being currently populated
                        //is the same as the one who's context we are in
                        //(based on outer loop) then make that the current plugin
                        //for the shell host
                        if (name == plugin.Name)
                        {
                            //this area can be used to give context to the outer loop since the
                            //shell here will ALWAYS be the one defined in the outer loop.  
                            //ie it is hit as many times as the outer loop
                            shell.Initialize(plugin);
                            shell.RegisterPlugin(plugin, true);


                        }
                        else
                        {
                            shell.RegisterPlugin(plugin, false);
                        }
                    }
                    catch (Exception ex)
                    {
                        string error = string.Format("2CB00383-5E16-41d3-B545-C94FAAC22DD6: unable to load plugin because {0} {1}", ex.Message, ex.StackTrace);
                        Logger.Log(error);
                        //IMPORTANT: fix dialog display issues
                    }
                }


                //add shell to window
                _window.AddPluginShell(name, shell);
            }
            
           
        }

        public override string GeCurrentRunnableUser()
        {
            if (_window != null)
                return _window.CurrentUser;
            else
                return "console";
        }

        public override void RecieveBroadcast(string application, string filter, string message)
        {
            CrossThreadDelegate ctd = delegate()
            {
                _window.PipelineBroadcastEvent(application, filter, message);
            };
            _window.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, ctd);            
        }

        public override void Shutdown()
        {
            _window.Close();
        }

        public override void UnhandledRecoveryStartup()
        {
            System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(_window);
        }

        /// <summary>
        /// used here to unload the currently running plugin
        /// </summary>
        public override void UnhandledRecoveryShutdown()
        {
            _window.UnloadCurrentPlugin();
        }

        public override void HideWaitUI()
        {
            if(_last_waitcontext == null)
                _window.StopWaiting();            
        }

        public override void ShowWaitUI()
        {
            _window.StartWaiting();
        }

        public override void PersistAfterError()
        {
            _window.ShowDialog();
        }

        public override void ShowWaitUI(object waitcontext)
        {
            if (_last_waitcontext == null)
            {
                _last_waitcontext = waitcontext;
                _window.StartWaiting();
            }
            else
            {
                //enqueue and register wait context
                this._wait_context_list.Add(waitcontext,waitcontext);
                _wait_q.Enqueue(waitcontext);
            }
        }

        public override void HideWaitUI(object waitcontext)
        {
            if (_last_waitcontext == waitcontext)
            {
                _window.StopWaiting();
                _last_waitcontext = null;

                do
                {
                    if (_wait_q.Count <= 0)
                        break;

                    object new_wait_context = _wait_q.Dequeue();
                    if (_wait_context_list.ContainsKey(new_wait_context))
                    {
                        _last_waitcontext = new_wait_context;
                        break;
                    }
                    
                   
                } while (true);
            }
            else
            {
                if (_wait_context_list.ContainsKey(waitcontext))
                {
                    _wait_context_list.Remove(waitcontext);
                }
            }
        }

        void ForceHide()
        {
            lock (this)
            {
                _wait_context_list = new Dictionary<object, object>();
                this._wait_q = new Queue<object>();
                _last_waitcontext = null;
                _window.StopWaiting();
            }

        }
    }

    //public class 
}